package user

import (
    "SmartSearch/internal/models"
    "SmartSearch/internal/repositories"
    "SmartSearch/internal/responses"
    "SmartSearch/internal/utils/jwt"
    "github.com/gin-gonic/gin"
    "golang.org/x/crypto/bcrypt"
    "net/http"
    "regexp"
    "strconv"
)

type Controller struct {
    departmentRepository *repositories.DepartmentRepository
    userRepository       *repositories.UserRepository
    roleRepository       *repositories.RoleRepository
}

func NewUserController() *Controller {
    return &Controller{
        departmentRepository: &repositories.DepartmentRepository{},
        userRepository:       &repositories.UserRepository{},
        roleRepository:       &repositories.RoleRepository{},
    }
}

func (u *Controller) Login(c *gin.Context) {
    var params struct {
        Username string `json:"username"`
        Password string `json:"password"`
    }
    if err := c.BindJSON(&params); err != nil {
        c.JSON(http.StatusOK, responses.GenFailResult("用户名或密码不能为空"))
        return
    }
    user := u.userRepository.FindByUsername(params.Username)
    if user == nil {
        c.JSON(http.StatusOK, responses.GenFailResult("用户不存在"))
        return
    }
    if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(params.Password)); err != nil {
        c.JSON(http.StatusOK, responses.GenFailResult("密码错误"))
        return
    }
    token, err := jwt.GenerateJwt(user.Id)
    if err != nil {
        return
    }
    result := map[string]interface{}{
        "token": token,
    }
    c.JSON(http.StatusOK, responses.GenSuccessResult(result))
}

func (u *Controller) Add(c *gin.Context) {
    var params struct {
        Username     string  `json:"username"`
        Password     string  `json:"password"`
        DepartmentId int64   `json:"departmentId"`
        Phone        string  `json:"phone,omitempty"`
        Name         string  `json:"name,omitempty"`
        Avatar       string  `json:"avatar,omitempty"`
        Type         int     `json:"type"`
        RoleIds      []int64 `json:"roleIds,omitempty"`
    }
    if err := c.BindJSON(&params); err != nil {
        c.JSON(http.StatusOK, responses.GenFailResult("参数解析错误"))
        return
    }
    if checkUsername(params.Username) {
        c.JSON(http.StatusOK, responses.GenFailResult("用户名不合法"))
        return
    }
    if checkPassword(params.Password) {
        c.JSON(http.StatusOK, responses.GenFailResult("密码不合法"))
        return
    }
    if u.userRepository.FindByUsername(params.Username) != nil {
        c.JSON(http.StatusOK, responses.GenFailResult("用户已存在"))
        return
    }
    if _, err := u.departmentRepository.FindById(params.DepartmentId); err != nil {
        c.JSON(http.StatusOK, responses.GenFailResult("部门不存在"))
        return
    }
    roles := u.roleRepository.FindByIds(params.RoleIds)
    passwordHash, _ := bcrypt.GenerateFromPassword([]byte(params.Password), bcrypt.DefaultCost)
    user := models.User{
        Username:                params.Username,
        Password:                string(passwordHash),
        DepartmentId:            params.DepartmentId,
        Phone:                   params.Phone,
        Name:                    params.Name,
        Avatar:                  params.Avatar,
        Type:                    params.Type,
        Enabled:                 true,
        AccountNonExpirable:     true,
        AccountNonLockable:      true,
        CredentialsNonExpirable: true,
        Roles:                   roles,
    }
    if err := u.userRepository.Add(&user); err != nil {
        c.JSON(http.StatusOK, responses.GenFailResult("用户添加失败"))
        return
    }
}

func (u *Controller) Del(c *gin.Context) {
    var params struct {
        Id int64 `json:"id"`
    }
    if err := c.BindJSON(&params); err != nil {
        c.JSON(http.StatusOK, responses.GenFailResult("参数解析错误"))
        return
    }
    if u.userRepository.FindById(params.Id) == nil {
        c.JSON(http.StatusOK, responses.GenFailResult("用户不存在"))
        return
    }
    if err := u.userRepository.Del(params.Id); err != nil {
        c.JSON(http.StatusOK, responses.GenFailResult("用户删除失败"))
        return
    }
    c.JSON(http.StatusOK, responses.GenSuccessResult(nil))
}

func (u *Controller) List(c *gin.Context) {
    username := c.Query("username")
    var departmentId *int64
    if v, err := strconv.ParseInt(c.Query("departmentId"), 10, 32); err == nil {
        departmentId = &v
    }
    phone := c.Query("phone")
    name := c.Query("name")
    var enable *bool
    if s, err := strconv.ParseBool(c.Query("enable")); err == nil {
        enable = &s
    }
    current, _ := strconv.ParseInt(c.DefaultQuery("current", "0"), 10, 32)
    pageSize, _ := strconv.ParseInt(c.DefaultQuery("pageSize", "10"), 10, 32)
    list := u.userRepository.GetList(username, departmentId, phone, name, enable, int32(current), int32(pageSize))
    c.JSON(http.StatusOK, responses.GenSuccessResult(list))
}

func (u *Controller) Update(c *gin.Context) {
    var params struct {
        Id           int64   `json:"id"`
        DepartmentId int64   `json:"departmentId"`
        Phone        string  `json:"phone,omitempty"`
        Name         string  `json:"name,omitempty"`
        Avatar       string  `json:"avatar,omitempty"`
        RoleIds      []int64 `json:"roleIds,omitempty"`
    }
    if err := c.BindJSON(&params); err != nil {
        c.JSON(http.StatusOK, responses.GenFailResult("参数解析错误"))
        return
    }
    user := u.userRepository.FindById(params.Id)
    if user == nil {
        c.JSON(http.StatusOK, responses.GenFailResult("用户不存在"))
        return
    }
    if user.DepartmentId != params.DepartmentId {
        if _, err := u.departmentRepository.FindById(params.DepartmentId); err != nil {
            c.JSON(http.StatusOK, responses.GenFailResult("部门不存在"))
            return
        } else {
            user.DepartmentId = params.DepartmentId
        }
    }
    if user.Phone != params.Phone {
        user.Phone = params.Phone
    }
    if user.Name != params.Name {
        user.Name = params.Name
    }
    if user.Avatar != params.Avatar {
        user.Avatar = params.Avatar
    }
    roles := u.roleRepository.FindByIds(params.RoleIds)
    user.Roles = roles
    if err := u.userRepository.Update(user); err != nil {
        c.JSON(http.StatusOK, responses.GenFailResult("修改用户失败"))
        return
    }
    c.JSON(http.StatusOK, responses.GenSuccessResult(nil))
}

func (u *Controller) UpdatePassword(c *gin.Context) {
    var params struct {
        Id       int64  `json:"id"`
        Password string `json:"password"`
    }
    if err := c.BindJSON(&params); err != nil {
        c.JSON(http.StatusOK, responses.GenFailResult("参数解析错误"))
        return
    }
    if checkPassword(params.Password) {
        c.JSON(http.StatusOK, responses.GenFailResult("密码不合法"))
        return
    }
    user := u.userRepository.FindById(params.Id)
    if user == nil {
        c.JSON(http.StatusOK, responses.GenFailResult("用户不存在"))
        return
    }
    passwordHash, _ := bcrypt.GenerateFromPassword([]byte(params.Password), bcrypt.DefaultCost)
    user.Password = string(passwordHash)
    if err := u.userRepository.Update(user); err != nil {
        c.JSON(http.StatusOK, responses.GenFailResult("更新密码失败"))
        return
    }
    c.JSON(http.StatusOK, responses.GenSuccessResult(nil))
}

func checkPassword(password string) (b bool) {
    if len(password) < 8 {
        return false
    }
    if ok, _ := regexp.MatchString("^[a-zA-Z0-9]{4,16}$", password); !ok {
        return false
    }
    return true
}

func checkUsername(username string) (b bool) {
    if len(username) < 6 {
        return false
    }
    if ok, _ := regexp.MatchString("^[a-zA-Z0-9]{4,16}$", username); !ok {
        return false
    }
    return true
}
